import axios, {isCancel} from 'axios'
import {ElMessage, ElLoading} from 'element-plus'
import type {
    AxiosInstance,
    AxiosRequestConfig,
    AxiosResponse,
    InternalAxiosRequestConfig,
    AxiosError
} from 'axios'

// 扩展请求配置类型，添加自定义配置选项
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
    noRepeat?: boolean    // 是否跳过重复请求检查
    noLoading?: boolean   // 是否显示加载状态
}

// 创建 axios 实例
const service: AxiosInstance = axios.create({
    // 基础请求路径：优先从环境变量获取
    baseURL: import.meta.env.VITE_API_BASE_URL as string || '/api',
    // 请求超时时间
    timeout: 10000,
    // 默认请求头
    headers: {
        'Content-Type': 'application/json;charset=utf-8'
    }
})

// 存储请求取消控制器的 Map
const abortControllerMap = new Map<string, AbortController>()

// 全局加载状态计数器和实例
let loadingCount = 0
let loadingInstance: ReturnType<typeof ElLoading.service> | null = null

// 显示全局加载状态
const showLoading = () => {
    if (loadingCount === 0) {
        loadingInstance = ElLoading.service({
            fullscreen: true,
            text: '加载中...',
            background: 'rgba(0, 0, 0, 0.7)'
        })
    }
    loadingCount++
}

// 隐藏全局加载状态
const hideLoading = () => {
    if (loadingCount > 0) {
        loadingCount--
    }
    if (loadingCount === 0 && loadingInstance) {
        loadingInstance.close()
        loadingInstance = null
    }
}

/**
 * 生成请求唯一标识
 * @param config 请求配置对象
 * @returns 拼接后的唯一字符串
 */
const getRequestKey = (config: AxiosRequestConfig): string => {
    const {method, url, params, data} = config
    return [
        method?.toUpperCase() || '',
        url || '',
        params ? JSON.stringify(params) : '',
        data ? JSON.stringify(data) : ''
    ].join('&')
}

// 请求拦截器
service.interceptors.request.use(
    (config: InternalAxiosRequestConfig & CustomAxiosRequestConfig) => {
        // 处理加载状态
        if (!config.noLoading) {
            showLoading()
        }

        // 处理重复请求
        const requestKey = getRequestKey(config)
        if (abortControllerMap.has(requestKey) && !config.noRepeat) {
            abortControllerMap.get(requestKey)?.abort()
            abortControllerMap.delete(requestKey)
        }

        // 创建新的取消控制器
        if (!config.noRepeat) {
            const controller = new AbortController()
            config.signal = controller.signal
            abortControllerMap.set(requestKey, controller)
        }

        // 添加 Token
        const accessToken = localStorage.getItem('accessToken')
        if (accessToken && config.headers) {
            config.headers.Authorization = `Bearer ${accessToken}`
        }

        return config
    },
    (error: AxiosError) => {
        hideLoading()
        console.error('请求拦截器错误:', error.message)
        return Promise.reject(error)
    }
)

// 响应拦截器
service.interceptors.response.use(
    (response: AxiosResponse) => {
        // 隐藏加载状态
        hideLoading()

        // 清理当前请求的取消控制器
        const requestKey = getRequestKey(response.config)
        abortControllerMap.delete(requestKey)

        // 提取后端返回的核心数据
        const res = response.data

        // 兼容无 code 字段的响应
        if (typeof res.code === 'undefined') {
            return res
        }

        // 按业务状态码处理
        if ([200, 0].includes(res.code)) {
            return res
        } else {
            const errorMsg = res.message || '请求失败'
            console.error('业务错误:', errorMsg)
            ElMessage.error(errorMsg)
            return Promise.reject(new Error(errorMsg))
        }
    },
    (error: AxiosError) => {
        // 隐藏加载状态
        hideLoading()

        // 清理当前请求的取消控制器
        if (error.config) {
            const requestKey = getRequestKey(error.config)
            abortControllerMap.delete(requestKey)
        }

        // 处理取消请求错误
        if (isCancel(error)) {
            const errorMsg = '请求已取消'
            console.log(errorMsg)
            return Promise.reject(new Error(errorMsg))
        }

        // 处理其他错误
        let errorMsg = '网络错误，请稍后重试'
        const axiosError = error as AxiosError

        if (axiosError.response) {
            switch (axiosError.response.status) {
                case 401:
                    errorMsg = '登录已过期，请重新登录'
                    localStorage.removeItem('accessToken')
                    localStorage.removeItem('refreshToken')
                    break
                case 403:
                    errorMsg = '没有权限执行该操作'
                    break
                case 404:
                    errorMsg = '请求的资源不存在'
                    break
                case 500:
                    errorMsg = '服务器内部错误'
                    break
                default:
                    errorMsg = `请求错误 (${axiosError.response.status})`
                    break
            }
        } else if (axiosError.message?.includes('timeout')) {
            errorMsg = '请求超时，请检查网络'
        }

        console.error('响应错误:', errorMsg)
        ElMessage.error(errorMsg)
        return Promise.reject(new Error(errorMsg))
    }
)

// 封装常用请求方法
const request = {
    /**
     * GET 请求封装
     * @param url 请求地址
     * @param params URL 参数
     * @param config 额外请求配置
     * @returns Promise<T>
     */
    get<T = any>(url: string, params?: any, config?: CustomAxiosRequestConfig): Promise<T> {
        return service.get(url, {params, ...config}).then(response => response.data)
    },

    /**
     * POST 请求封装
     * @param url 请求地址
     * @param data 请求体
     * @param config 额外请求配置
     * @returns Promise<T>
     */
    post<T = any>(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise<T> {
        return service.post(url, data, config).then(response => response.data)
    },

    /**
     * PUT 请求封装
     * @param url 请求地址
     * @param data 请求体
     * @param config 额外请求配置
     * @returns Promise<T>
     */
    put<T = any>(url: string, data?: any, config?: CustomAxiosRequestConfig): Promise<T> {
        return service.put(url, data, config).then(response => response.data)
    },

    /**
     * DELETE 请求封装
     * @param url 请求地址
     * @param params URL 参数
     * @param config 额外请求配置
     * @returns Promise<T>
     */
    delete<T = any>(url: string, params?: any, config?: CustomAxiosRequestConfig): Promise<T> {
        return service.delete(url, {params, ...config}).then(response => response.data)
    },

    /**
     * 取消所有未完成的请求
     */
    cancelAllRequests(): void {
        abortControllerMap.forEach(controller => controller.abort())
        abortControllerMap.clear()
        loadingCount = 0
        if (loadingInstance) {
            loadingInstance.close()
            loadingInstance = null
        }
    }
}

// 登录接口定义
export interface LoginRequest {
    username: string
    password: string
}

export interface UserInfo {
    username: string
    role: 'user' | 'administrator' | 'tgs'
    expiration: number
}

export interface LoginResponse {
    code: number
    message: string
    data: {
        accessToken: string
        refreshToken: string
        userInfo: UserInfo
    }
}

/**
 * 用户登录接口
 * @param data 登录表单数据
 * @returns Promise<LoginResponse>
 */
export const loginApi = (data: LoginRequest): Promise<LoginResponse> => {
    return request.post<LoginResponse>('/auth/login', data)
}

export default request
